/*
 * ml20dll
 * This source code is under the GNU Public License (GPL).
 * Written by Ramiro Polla
 * Initial release: july 14th, 2005
 *
 * this dll reads ml20 files
 */

#ifndef ML20DLL_H
#define ML20DLL_H

#include <windows.h>
#include <vfw.h>
#include <stdio.h>
#include <inttypes.h>

/**************************** Structures **********************************/

typedef struct kfret {
    uint8_t imagebuffer[0x38400];
    int height;
    int width;
} imgret_t, *imgret_p;

typedef struct msn_s {
    HANDLE rp;
    DWORD pid;
    DWORD procaddress;
    char *wmv;
} msn_t;

typedef struct {
    //kernel functions
    HMODULE (__stdcall *LoadLibraryX)(LPCSTR);
    BOOL (__stdcall *FreeLibrary)(HMODULE);
    FARPROC (__stdcall *GetProcAddress)(HMODULE, LPCSTR);

    //vfw functions
    BOOL (__stdcall *ICInstall)( DWORD fccType,DWORD fccHandler, LPARAM lParam, LPSTR szDesc, UINT wFlags );
    HIC (__stdcall *ICOpen)( DWORD fccType, DWORD fccHandler, UINT wMode );
    DWORD (__cdecl *ICDecompress) ( HIC hic, DWORD dwFlags, LPBITMAPINFOHEADER lpbiFormat, LPVOID lpData, LPBITMAPINFOHEADER lpbi, LPVOID lpBits );
    LRESULT (__stdcall *ICClose)( HIC hic );
    LRESULT (__stdcall *ICSendMessage)( HIC hic, UINT wMsg, DWORD dw1, DWORD dw2 );
    BOOL (__stdcall *ICRemove)( DWORD fccType, DWORD fccHandler, UINT wFlags );

    //function names (there has to be a better way)
    char vfw[16];
    char icopen[7];
    char icinstall[10];
    char icdecompress[13];
    char icclose[8];
    char icsendmessage[14];
    char icremove[9];

    //headers
    BITMAPINFOHEADER ML20;
    BITMAPINFOHEADER BITM;

    //pointers to injdata and threads inside msn messenger
    LPVOID    remotedata;
    LPVOID    remoteout;
    LPVOID    remotecode;
    uint8_t *in;
    uint8_t *out;

    //ML20's HIC
    HIC hIC;

    //address of ml20 codec inside msn messenger
    // DEPENDS ON MSN VERSION
    long ml20proc;

    HINSTANCE vfwdll;
    msn_t msnt;
} INJDATA;

// ML20 header struct
typedef struct {
    uint16_t    ss;         //struct size
    uint16_t    width;      //frame width
    uint16_t    height;     //frame height
    uint16_t    ff;         //kf + some other info
    uint32_t    size;       //size of data
    uint32_t    signature;  //ML20
    uint32_t    u3;         //?
    uint32_t    time;       //time
} ML20H;

// ML20 frame struct
typedef struct {
    ML20H h;
    uint8_t *data;
    unsigned int size;
} ML20F;

// first bytes of ML20 frame
typedef struct {
    uint16_t    coeffs;
    uint16_t    quality;
    int16_t     width;
    int16_t     height;
    uint32_t    constant;
    uint32_t    nkf;
} frameinfo;

/* UDP header*/
struct udphdr {
    u_short uh_sport;   // Source port
    u_short uh_dport;   // Destination port
    u_short uh_len;     // Datagram length
    u_short uh_crc;     // Checksum
};

#pragma pack( push, ml20dll_pack )
#pragma pack( 1 )
//      TTTTTTTTTTT FF NN TO
//05 49 2d 3d 87 02 0a 05 06
struct udpinthdr {
    uint16_t unk;
    uint32_t time;
    uint8_t frame_num;
    uint8_t frame_part;
    uint8_t frame_tot;
};

typedef struct {
    uint8_t code;               //code
    uint16_t retransmission:5;  //(0000000000011111) retransmission on case of error
    uint16_t size:11;           //(1111111111100000) payload size

    uint8_t frame_part:6;       //(00111111) frame part
    uint8_t nkeyframe:2;        //(11000000) !keyframe?

    uint32_t timestamp;         //timestamp
    uint8_t frame_num;          //frame number
    uint8_t frame_tot;          //packets in frame
} vcinthdr;
#pragma pack( pop, ml20dll_pack )

//virtual ml20 frame
typedef struct vframe_s {
    struct vframe_s *nf;     // next frame
    struct vframe_s *pf;     // previous frame
    struct vframe_s *nkf;    // next key frame
    struct vframe_s *mkf;    // my keyframe
    struct vframe_s *pkf;    // previous key frame
    unsigned int filepos;   // position in file // or (udps *)
    unsigned int fnum;      // frame number
    unsigned int time;      // frame time
    unsigned int real_time; // fixed time (starting at 0)
} vframe_t;

//virtual ml20 stream
typedef struct vstream_s {
    FILE *file;     // FILE
    vframe_t *ff;   // first frame
    vframe_t *lf;   // last frame

    LONG width;
    LONG height;

    char *fullname; // full file name
    unsigned int eof;

    int flags;
} vstream_t;

#define VSTREAM_UDP (1 << 0)
#define VSTREAM_VC  (1 << 1)

struct wmv3bmi {
    BITMAPINFOHEADER bm;
    uint8_t data[6];    //last 6 bytes are still unknown
};

typedef struct decoder_s {
    BITMAPINFOHEADER ML20;  // ML20 BITMAPINFOHEADER
    BITMAPINFOHEADER BITM;  // BITM BITMAPINFOHEADER
    struct wmv3bmi WMV3;
    HIC hIC;                // Codec Handle

    uint8_t *kol;           // output buffer

    vstream_t *vstream;     // last vstream used
    vframe_t *vframe;       // last vframe used
    vframe_t *kframe;       // last keyframe decoded
    vframe_t *dvframe;      // last actually decoded vframe

    vframe_t *in;           // in frame
    vframe_t *out;          // out frame

    INJDATA *injdata;

    int flags;
} decoder_t;

#define DECODER_SELECTION   (1 << 1)
#define DECODER_REMOTE      (1 << 2)

typedef struct udp_structs {
    struct udp_structs *next;       // next udp_structs
    struct udp_structs *previous;   // previous udp_structs
    struct udpinthdr udp_hdr;       // frame information
    unsigned int filepos;          // position on file after frame information
    unsigned int size;             // number of bytes to read at filepos
    unsigned int length;           // size + sizeof(udp_hdr)
} udps;

/***************************** Macros *************************************/

#define IS_SET(vector, flag)    ((vector) & (flag))
#define SET_BIT(vector, flag)   ((vector) |= (flag))
#define UNSET_BIT(vector, flag) ((vector) &= (-1) - (flag))

#define READ_DATA       (1 << 0)
#define READ_SEEK_IN    (1 << 1)
#define READ_SEEK_OUT   (1 << 2)
#define READ_SEEK_FIRST (1 << 3)
#define READ_RET_IN     (1 << 4)
#define READ_UDP        (1 << 5)

#define FOURCC_ML20 mmioFOURCC( 'M', 'L', '2', '0' )
#define FOURCC_LM20 mmioFOURCC( 'L', 'M', '2', '0' )

/************************* Function prototypes ****************************/

/* ml20dll.dll */
int decode_frame( decoder_t *decoder, vframe_t *vframe );
int decode_keyframe( decoder_t *decoder, vframe_t *vframe );
vstream_t *build_vstream( char *fname );
int vstream_new_frame( vstream_t *vstream );
void kill_vstream( vstream_t *vstream );
decoder_t *new_decoder( vstream_t *vstream, msn_t *msnt );
void kill_decoder( decoder_t *decoder );
imgret_p ml20_first_keyframe( char *fullname, msn_t *msnt );
void dump_frame( unsigned int filepos, vstream_t *vstream, ML20F *ml20f );

char *ml20dll_version( );

#endif
